package com.aji.service.impl;

import com.aji.entity.*;
import com.aji.mapper.LocMapper;
import com.aji.mapper.ModelMapper;
import com.aji.vo.*;
import com.opencsv.bean.CsvToBeanBuilder;
import com.aji.config.FileEnvConfig;
import com.aji.dto.ElementAddDto;
import com.aji.dto.ElementChangeDto;
import com.aji.dto.ElementDto;
import com.aji.mapper.ElementMapper;
import com.aji.result.PageResult;
import com.aji.service.ElementService;
import com.aji.utills.CsvUtills;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Slf4j
@Service
public class ElementServiceImpl implements ElementService {
    @Autowired
    private FileEnvConfig fileEnvConfig;
    @Autowired
    ElementMapper elementMapper;
    @Autowired
    private ModelMapper modelMapper;
    @Autowired
    private LocMapper locMapper;
    @Override
    public PageResult pageQuery(ElementDto elementDto,int page1,int pageSize) {
        log.info("element模糊查询service:{},{},{}",elementDto.toString(),page1,pageSize);
        PageHelper.startPage(page1,pageSize);
        List<ElementVo> elementVoList = elementMapper.pageQuery(elementDto);
        Page<ElementVo> page = (Page<ElementVo>) elementVoList;
        long totol=page.getTotal();
        List<ElementVo>records=page.getResult();
        return new PageResult(totol,records);
    }

    @Override
    public void deleteByIds(List<Integer> ids) {
        log.info("element删除service:{}",ids.toString());
        elementMapper.deleteByIds(ids);
        elementMapper.deleteMoreByIds(ids);
    }

    @Override
    public void add(ElementAddDto elementAddDto) {
        log.info("element添加service:{}",elementAddDto.toString());
        LocalDateTime createTime =  LocalDateTime.now();
        Element element = Element.builder()
                        .contents(elementAddDto.getContents())
                .element(elementAddDto.getElement())
                .recId(elementAddDto.getRecId())
                .locId(elementAddDto.getLocId())
                        .typeId(elementAddDto.getTypeId())
                                .createTime(createTime)
                .batchId(elementAddDto.getBatchId()).build();
        elementMapper.add(element);
        Integer elementId = elementMapper.getLastInsertId(); // 假设此方法返回 LAST_INSERT_ID()
        element.setId(elementId);

        // 使用获取的 ID
        ElementOrigin elementOrigin = ElementOrigin.builder()
                .elementId(element.getId())
                .originId(elementAddDto.getOriginId())
                .build();
        elementMapper.addMore(elementOrigin);
    }

    @Override
    public void upDate(ElementChangeDto element1,int id) {
        log.info("element修改service:{}",element1.toString());
        LocalDateTime changeTime =  LocalDateTime.now();
        Element element = Element.builder()
                .id(id)
                .contents(element1.getContents())
                .element(element1.getElement())
                .recId(element1.getRecId())
                .locId(element1.getLocId())
                .typeId(element1.getTypeId())
                .changeTime(changeTime)
                .batchId(element1.getBatchId()).build();
        elementMapper.upDate(element);
        ElementOrigin elementOrigin = ElementOrigin.builder()
                .elementId(id)
                .originId(element1.getOriginId()).build();
        elementMapper.updateMore(elementOrigin);

    }

    @Override
    public ElementByIdVoDdd selectById(int id) {
        ElementByIdVo elementByIdVo = elementMapper.selectById(id);
        ElementByIdVoDdd elementByIdVoDdd = new ElementByIdVoDdd();
        BeanUtils.copyProperties(elementByIdVo, elementByIdVoDdd);
        elementByIdVoDdd.setElement(Arrays.asList(elementByIdVo.getElement().split("\\t")));

        return elementByIdVoDdd;
    }

    @Override
    public List<ElementVo> selectCon(ElementDto elementDto) {
        return elementMapper.pageQuery(elementDto);
    }

    /**
     * 模型训练
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    public void trainEle(List<Integer> modelIds) throws IOException, InterruptedException {
        for (Integer id: modelIds){
            String modelName = modelMapper.selectById(id);
            String code = modelMapper.selectCode(id);//模型简称
            String modelTrainFile = code + fileEnvConfig.getModelTrainFile();
            String EnvConfig = fileEnvConfig.getModelEnv()+"\\"+modelName;
            String trainFile = EnvConfig+fileEnvConfig.getTrainFile();
            List<ElementTrain>elementTrainList = elementMapper.selectAll();
            CsvUtills.wCsv(trainFile,elementTrainList);
            ProcessBuilder processBuilder = new ProcessBuilder(fileEnvConfig.getPythonEnv(), modelTrainFile);
            processBuilder.directory(new File(EnvConfig));
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            System.out.println("模型训练执行完成，退出码：" + exitCode);
        }

    }


    @Override
    public ResponseEntity<List<ElementRunVo>> testEle(List<Integer> modelIds, List<Integer> ids) throws IOException, InterruptedException {
        // 创建一个新的列表，只包含contents、prediction和modelName
        List<ElementRunVo> filteredList = new ArrayList<>();
        for (Integer modelId : modelIds) {
            String modelName = modelMapper.selectById(modelId);
            System.out.println(modelName);
            String code = modelMapper.selectCode(modelId);//模型简称
            String modelTestFile = code + fileEnvConfig.getModelTestFile();
            System.out.println(modelTestFile);
            String EnvConfig = fileEnvConfig.getModelEnv()+"\\"+modelName;
            String testFile = EnvConfig+fileEnvConfig.getTestFile();
            List<ElementTest>elementTestList = elementMapper.selectByIds(ids);
            CsvUtills.wCsvTest(testFile,elementTestList);

            ProcessBuilder processBuilder = new ProcessBuilder(fileEnvConfig.getPythonEnv(), modelTestFile);
            processBuilder.directory(new File(EnvConfig));
            Process process = processBuilder.start();
            int exitCode = process.waitFor();
            System.out.println("模型预测执行完成，退出码：" + exitCode);

            //获取预测结果文件路径
            String preFile = EnvConfig + fileEnvConfig.getPreFile();
            Path filePath = Paths.get(preFile);

            //检查文件是否存在
            if(!Files.exists(filePath)){
                throw new IOException("预测结果文件不存在");
            }

            //读取CSV文件并解析为ElementRunVo对象列表
            List<ElementRunVo> resultList = new ArrayList<>();
            try (FileReader reader = new FileReader(filePath.toFile())) {
                resultList = new CsvToBeanBuilder(reader)
                        .withType(ElementRunVo.class)
                        .build()
                        .parse();
            } catch (IOException e) {
                e.printStackTrace();
                throw new IOException("读取预测结果文件失败", e);
            }
            //将预测结果加入到resultList中
            for (ElementRunVo element : resultList) {
                ElementRunVo filteredElement = new ElementRunVo();
                filteredElement.setContents(element.getContents());
                int prediction = Integer.parseInt(element.getPrediction());
                String oresName3 = locMapper.selectOres3Name(prediction);
                filteredElement.setPrediction(oresName3);
                filteredElement.setModelName(modelMapper.selectById(modelId));
                filteredList.add(filteredElement);
            }
        }

        // 设置响应头信息等，返回包含过滤后ElementTest列表的ResponseEntity
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return new ResponseEntity<>(filteredList, headers, HttpStatus.OK);
    }

    @Override
    public void addBatch(List<ElementAddDto> elementAddDtoList) {
        for (ElementAddDto elementAddDto: elementAddDtoList) {
            add(elementAddDto);
        }
    }

    @Override
    public ElementByIdVo selectByIdNew(int id) {
        return elementMapper.selectById(id);
    }

    @Override
    public ResponseEntity<List<ElementBatchVo>> uploadFile(MultipartFile file) {
        try {
            List<ElementBatchVo> elementList = new ArrayList<>();

            String fileName = file.getOriginalFilename();

            if (fileName.endsWith(".csv")) {
                Reader reader = new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8);
                CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withFirstRecordAsHeader());

                for (CSVRecord csvRecord : csvParser) {
                    StringBuilder mergedString = new StringBuilder();
                    for (int i = 7; i < csvRecord.size(); i++) {
                        mergedString.append(csvRecord.get(i)); // 获取当前列数据
                        if (i < csvRecord.size() - 1) {
                            mergedString.append("\t"); // 除了最后一列，其他列之间使用制表符分隔
                        }
                    }
                    mergedString.append("\n"); // 每一行处理完后，换行

                    ElementBatchVo elementBatchVo = ElementBatchVo.builder().contents(csvRecord.get("样品编号"))
                            .typeName(csvRecord.get("样品类别"))
                            .ores1Name(csvRecord.get("成矿带"))
                            .ores2Name(csvRecord.get("矿带"))
                            .ores3Name(csvRecord.get("矿点"))
                            .recName(csvRecord.get("识别状态"))
                            .element(mergedString.toString())
                            .originName(csvRecord.get("样品来源")).build();

                    elementList.add(elementBatchVo);
                }

                // 关闭解析器
                csvParser.close();
            }

            else if (fileName.endsWith(".xlsx") || fileName.endsWith(".xls")) {
                Workbook workbook = new XSSFWorkbook(file.getInputStream());  // 适用于 .xlsx 格式
                Sheet sheet = workbook.getSheetAt(0);  // 获取第一个 sheet

                for (Row row : sheet) {
                    // 跳过标题行
                    if (row.getRowNum() == 0) continue;
                    // 创建一个StringBuilder来收集从第七列到最后一列的数据
                    StringBuilder elementData = new StringBuilder();
                    int lastColumnIndex = row.getLastCellNum();
                    for (int i = 7; i < lastColumnIndex; i++) { // 从第七列开始
                        Cell cell = row.getCell(i);
                        if (cell != null) {
                            switch (cell.getCellType()) {
                                case STRING:
                                    elementData.append(cell.getStringCellValue());
                                    break;
                                case NUMERIC:
                                    elementData.append(cell.getNumericCellValue());
                                    break;
                                case BOOLEAN:
                                    elementData.append(cell.getBooleanCellValue());
                                    break;
                                default:
                                    elementData.append("");
                            }
                            if (i < lastColumnIndex - 1) {
                                elementData.append("\t"); // 在列之间添加制表符
                            }
                        }
                    }
                    log.info("element" + elementData);

                    ElementBatchVo elementBatchVo = ElementBatchVo.builder()
                            .contents(row.getCell(0).getStringCellValue())  // 样品编号在第一列
                            .typeName(row.getCell(1).getStringCellValue())  // 样品类别在第二列
                            .ores1Name(row.getCell(2).getStringCellValue())  // 成矿带在第三列
                            .ores2Name(row.getCell(3).getStringCellValue())  // 矿带在第四列
                            .ores3Name(row.getCell(4).getStringCellValue())  // 矿点在第五列
                            .recName(row.getCell(5).getStringCellValue())  // 识别状态在第六列
                            .originName(row.getCell(6).getStringCellValue())  // 样品来源在第七列
                            .element(elementData.toString())
                            .build();
                    elementList.add(elementBatchVo);
                }
                workbook.close();
            }
            return ResponseEntity.ok(elementList);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        }
    }
}
